﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;

namespace DotNet.Utilities.反射帮助类
{
    
   
     public class ReflectionTest<T>where T:class   
     { 
         //得到该类的所有属性
         




         /// <summary>  
         /// Assembly类的使用  
         /// </summary>  
         public void AssemblyTest()  
         {  
             Console.WriteLine("\t\t------------Assembly类的使用-------------");  
             Console.WriteLine();  
   
             //获取当前所执行代码的程序集信息  
             Assembly myAssembly=Assembly.GetExecutingAssembly();  
             Console.WriteLine("获取程序集位置："+myAssembly.CodeBase);  
             Console.WriteLine("获取程序集的入口点："+myAssembly.EntryPoint);  
             Console.WriteLine("获取程序集的显示名称："+myAssembly.FullName);  
             Console.WriteLine("获取包含当前程序集清单的模块："+myAssembly.ManifestModule);              
             Console.WriteLine("获取URL，表示基本代码的转义符："+myAssembly.EscapedCodeBase);  
             Console.WriteLine("获取此程序集的证据："+myAssembly.Evidence);  
             Console.WriteLine("获取当前程序集的授予权："+myAssembly.PermissionSet);  
             Console.WriteLine("当前程序集是否从缓存中加载的："+myAssembly.GlobalAssemblyCache.ToString());  
             Console.WriteLine("加载程序集主机上下文："+myAssembly.HostContext);  
             Console.WriteLine("CRL版本："+myAssembly.ImageRuntimeVersion);  
             Console.WriteLine("当前程序集是否通过反射得到的："+myAssembly.IsDynamic);  
             Console.WriteLine("当前程序集是否是完全信任的方式加载的："+myAssembly.IsFullyTrusted);  
             Console.WriteLine("清单的已加载路径："+myAssembly.Location);  
             Console.WriteLine("获取当前程序集的授予集："+myAssembly.PermissionSet);  
             Console.WriteLine("当前程序集是否加载到只反射上下文中："+myAssembly.ReflectionOnly);  
             Console.WriteLine("CLR对当前程序集强制执行的安全规则集："+myAssembly.SecurityRuleSet);  
             Console.WriteLine();  
   
             //获取当前程序集的名称及信息  
             AssemblyName asmName=myAssembly.GetName();  
             Console.WriteLine("获取或设置程序集的简单名称："+asmName.Name);  
             Console.WriteLine("获取或设置程序集的全名："+asmName.FullName);  
             Console.WriteLine("获取或设置程序集的URL位置："+asmName.CodeBase);  
             Console.WriteLine("获取或设置程序集的主版本号、次版本号、内部版本号和修订版本号：{ ",asmName.Version);  
   
               
             Console.WriteLine("获取或设置程序集支持的区域性："+asmName.CultureInfo);  
             Console.WriteLine("获取URL，包括表示基本代码的转义符："+asmName.EscapedCodeBase);  
             Console.WriteLine("获取或设置程序集的特性："+asmName.Flags);  
             Console.WriteLine("获取或设置程序集的清单使用的哈希算法："+asmName.HashAlgorithm);  
             Console.WriteLine("获取或设置为程序集的创建强名称签名的加密公钥/私钥对："+asmName.KeyPair);  
             Console.WriteLine("获取或设置程序集的可执行文件的目标平台的处理器和每字位数："+asmName.ProcessorArchitecture);  
             Console.WriteLine("获取或设置程序集同其他程序的兼容性相关的信息："+asmName.VersionCompatibility);  
             Console.WriteLine();  
   
             //获取当前程序集的版本相关信息  
             System.Version asmVersion=asmName.Version;  
             Console.WriteLine("获取当前程序集的主版本号："+asmVersion.Major);  
             Console.WriteLine("获取当前程序集的次版本号："+asmVersion.Minor);  
             Console.WriteLine("获取当前程序集的内部版本号："+asmVersion.Build);  
             Console.WriteLine("获取当前程序集的修订版本号："+asmVersion.MajorRevision);  
         }  
   
         /// <summary>  
         /// Type 类：检索类信息  
         /// </summary>  
         public void TypeTest()  
         {  
             Console.WriteLine("\t\t------------Type类的使用-------------");  
             Console.WriteLine();  
   
             Type myType=Type.GetType("反射.WeiMei");  
   
             //检索信息  
             Console.WriteLine("获取当前成员名称："+myType.Name);  
             Console.WriteLine("获取当前完全限定名（不包括程序集）："+myType.FullName);  
             Console.WriteLine("获取当前TYPE所在的命名空间："+myType.Namespace);  
             Console.WriteLine("获取当前TYPE关联的GUID："+myType.GUID);  
             Console.WriteLine("获取在其中定义在当前模块："+myType.Module);  
             Console.WriteLine("获取该成员的类对象："+myType.ReflectedType);  
   
             //检索类成员  
             Console.WriteLine("获取方法相关信息：{ ",myType.GetMethod("MetName").ToString());  
             Console.WriteLine("获取属性相关信息：{ ",myType.GetProperty("ProName").ToString());  
             Console.WriteLine("获取字段相关信息：{ ",myType .GetField("mName",BindingFlags.NonPublic|BindingFlags.Instance).ToString());  
             Console.WriteLine();  
             Type myThis=this.GetType();  
         }  
   
         /// <summary>  
         /// 访问类成员  
         /// </summary>  
         public void ClassMemberInfo()  
         {  
             //指定被访问的类  
             //Type WMtype=Type.GetType("反射.WeiMei");//使用这个时无法获取属性值  
             WeiMei myWeiMei=new WeiMei();  
             Type WMtype=myWeiMei.GetType();  
             Console.WriteLine("\t\t------------MemberInfo访问类的所有成员-------------");  
             Console.WriteLine();  
             //MemberInfo类：遍历被访问的类的所有成员  
             MemberInfo[] members=WMtype.GetMembers(BindingFlags.Public|BindingFlags.NonPublic|BindingFlags.Static|BindingFlags.Instance|BindingFlags.DeclaredOnly);  
             foreach(MemberInfo member in members)  
             {  
                 Console.WriteLine("成员名称：{ -----成员类型：{ ",member.Name,member.MemberType);  
             }  
             Console.WriteLine();  
             Console.WriteLine("\t\t------------MethodInfo访问类的方法-------------");  
             Console.WriteLine();  
   
             MethodInfo[] methods=WMtype.GetMethods(BindingFlags.Public|BindingFlags.NonPublic|BindingFlags.Static|BindingFlags.Instance|BindingFlags.DeclaredOnly);  
             foreach(MethodInfo method in methods)  
             {  
                 Console.WriteLine("方法名称：{ -----成员类型：{ ",method.Name,method.ReturnType);  
             }  
             Console.WriteLine();   
   
             Console.WriteLine("\t\t------------PropertyInfo访问类的属性-------------");  
             Console.WriteLine();  
             PropertyInfo[] propertys=WMtype.GetProperties(BindingFlags.Public|BindingFlags.NonPublic|BindingFlags.Static|BindingFlags.Instance|BindingFlags.DeclaredOnly);  
             foreach(PropertyInfo property in propertys)  
             {  
                 Console.WriteLine("属性名称：{ -----属性类型：{ -----属性值：{ ",property.Name,property.PropertyType,property.GetValue(myWeiMei,null));  
             }  
             Console.WriteLine();  
             Console.WriteLine("\t\t------------FieldInfo访问类的字段-------------");  
             Console.WriteLine();  
             FieldInfo[] fields=WMtype.GetFields(BindingFlags.Public|BindingFlags.NonPublic|BindingFlags.Static|BindingFlags.Instance|BindingFlags.DeclaredOnly);  
             foreach(FieldInfo field in fields)  
             {  
                 Console.WriteLine("字段名称：{ -----字段类型：{ ",field.Name,field.FieldType);  
             }  
   
             Console.WriteLine("\t\t------------ConstructorInfo访问类的构造函数-------------");  
             Console.WriteLine();  
   
             ConstructorInfo[] constructors=WMtype.GetConstructors(BindingFlags.Public|BindingFlags.NonPublic|BindingFlags.Static|BindingFlags.Instance|BindingFlags.DeclaredOnly);  
             foreach(ConstructorInfo constructor in constructors)  
             {  
                 Console.WriteLine("构造函数：{ -----构造函数类型：{ ",constructor.Name,constructor.MemberType);  
             }  
               Console.WriteLine();   
             Console.WriteLine("\t\t------------MemberInfo访问类的构造函数-------------");  
             Console.WriteLine();  
             EventInfo[] eventinfos=WMtype.GetEvents(BindingFlags.Public|BindingFlags.NonPublic|BindingFlags.Static|BindingFlags.Instance|BindingFlags.DeclaredOnly);  
             foreach(EventInfo eventinfo in eventinfos)  
             {  
                 Console.WriteLine("事件名称：{ ------成员类型：{ ",eventinfo.Name,eventinfo.MemberType);  
             }  
             Console.WriteLine();  
               
             Console.WriteLine("\t\t------------MemberInfo访问类的构造函数-------------");  
             Console.WriteLine();  
             MethodInfo myMethod=WMtype.GetMethod("TestName");  
             ParameterInfo[] parameters=myMethod.GetParameters();
             int count = 0;  
             foreach(ParameterInfo param in parameters)  
             {  
                 count++;  
                 Console.WriteLine("参数"+count+" 名称：{ -----类型：{ ",param.Name,param.ParameterType);  
             }  
             Console.WriteLine();  
         }  
   
         /// <summary>  
         /// 调用类成员  
         /// </summary>  
         public void OperMembers()  
         {  
             //指定被访问的类  
             WeiMei weiMeiObj=new WeiMei();  
             Type WMtype=weiMeiObj.GetType();  
             //Type WMtype=Type.GetType("反射.WeiMei");  
             //操作方法  
             string[] parName=new string[]{"WeiMeiHua"};//方法参数的值  
             MethodInfo method=WMtype.GetMethod("MetName");  
             method.Invoke(weiMeiObj,parName);  
             Console.WriteLine("操作方法改变值后为：{ ",weiMeiObj.ProName);  
   
             //操作属性  
             PropertyInfo proper=WMtype.GetProperty("ProName");  
             proper.SetValue(weiMeiObj,"HuaWeiMei",null);  
             //proper.GetValue(weiMeiObj,null);  
             Console.WriteLine("操作属性改变值后为：{ ",weiMeiObj.ProName);  
   
             //操作字段  
             FieldInfo field=WMtype.GetField("mName",BindingFlags.Instance|BindingFlags.NonPublic);  
             field.SetValue(weiMeiObj,"WeiMei");  
             //field.GetValue(weiMeiObj);  
             Console.WriteLine("操作字段改变值后为：{ ",weiMeiObj.ProName);  
   
             //操作事件  
             EventInfo eventinfo=WMtype.GetEvent("WMShout");  
             Console.WriteLine("声明该成员的类："+eventinfo.DeclaringType);  
             Console.WriteLine("事件名称："+eventinfo.Name);  
             Console.WriteLine("事件类型："+eventinfo.MemberType);  
   
             //操作构造函数  
             ConstructorInfo constructor=WMtype.GetConstructor(System.Type.EmptyTypes);  
         }  
     }  
   
     /// <summary>  
     /// 被访问的类  
     /// </summary>  
     public class WeiMei  
     {  
         //字段  
         private string mName;  
         private string mSex;  
         private int mAge;  
   
         public WeiMei()  
         {  
             mName="LiuWeiMei";  
             mSex="gril";  
             mAge= 10;  
         }  
   
         public WeiMei(string name,string sex,int age)  
         {  
             mName=name;  
             mSex=sex;  
             mAge=age;  
         }  
   
         public string ProName  
         {  
             get{return mName;}  
             set{mName=value;}  
         }  
   
         public string ProSex  
         {  
             get{return mSex;}  
             set{mSex=value;}  
         }  
   
         public int ProAge  
         {  
             get{return mAge;}  
             set{mAge=value;}  
         }  
   
         private string ProLoveYou  
         {  
             get{return "这是一个秘密，只有我知道";}  
         }  
   
         public string MetName(string herName)  
         {  
             this.mName=herName;  
             return mName;  
         }  
   
         public string MetSex(string herSex)  
         {  
             this.mSex=herSex;  
             return mSex;  
         }  
   
         public int MetAge(int herAge)  
         {  
             this.mAge=herAge;  
             return mAge;  
         }  
   
         public string TestName(string herName,int like,float love)  
         {  
             this.mName=herName;  
             return mName;  
         }  
   
         public delegate string WMName(string wmName);  
   
         public event WMName WMShout;  
         private event WMName WMLove;    
       
 }  

    public class ReflectionHelper<T> where T:class
    {
        /// <summary>
        /// 得到该对象的所有的属性
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <returns></returns>
        public static PropertyInfo[] GetPropertyInfos()
        {
            Type ty = typeof(T);
            if (ty != null)
            {
                return ty.GetProperties();
            }
            return null;
        }
      
        /// <summary>
        ///  根据键值对进行相应的赋值,例如ReflectionHelper<ClassInfo>(dic,)
        /// </summary>
        /// <param name="dic">键值对的值</param>
        /// <param name="t">要给类付属性值的对象</param>
        public static void SetPropertyValueByDic(Dictionary<string,string> dic,T t)
        {
            PropertyInfo[] pis=GetPropertyInfos();//得到所有的属性
            foreach (var key in dic.Keys)
            {
               var pi=pis.FirstOrDefault(x => x.Name == key);
                //var type=pi.PropertyType;
                pi.SetValue(t,(object)dic[key], null);
            }
        }
        //根据名字去实例化对象
        public static object NewObjectByFullName(string fullName)
        {
          
            Type t = Type.GetType(fullName);
            var ctor= t.GetConstructor(Type.EmptyTypes);//得到构造函数
            return ctor.Invoke(null);
        }
        /// <summary>
        /// 给属性赋值
        /// </summary>
        /// <param name="source">该属性属于那个对象</param>
        /// <param name="property">属性的名字</param>
        /// <param name="value">属性的值</param>
        /// <param name="prefix"></param>
        /// <param name="stringBasedValue">是否为集合</param>
        public static void SetPropertyValue(object source, string property, object value, string prefix = null, bool stringBasedValue = false)
        {
            try
            {
                List<string> level = new List<string>();
                if (property.Contains('.'))//将属性加入到level的集合里面
                {
                    level.AddRange(property.Split('.'));
                }
                else
                {
                    level.Add(property);
                }
                //非空的话 加入到第一个位置
                if (!string.IsNullOrWhiteSpace(prefix))
                {
                    level.Insert(0, prefix);
                }
                object temp = source;//将对象赋值给Temp
                Type tempType = source.GetType();//得到对象的类型
                for (int i = 0; i < level.Count - 1; i++)//循环遍历属性
                {
                    var pro = tempType.GetProperty(level[i]);//根据属性的名字得到属性对象
                    if (pro != null)//当得到属性的对象的时候
                    {
                        var va = pro.GetValue(temp, null);//得到对象的值
                        if (va != null)//如果得到了值 将值给Temp;
                        {
                            temp = va;
                        }
                        else
                        {//创建属性对象实例化
                            var newInstance = va.GetType().GetConstructor(Type.EmptyTypes).Invoke(null);
                            pro.SetValue(temp, newInstance, null);//给对象设置初始化值 初始化该属性的一个空的构造函数
                            temp = newInstance;//没有的值的话 初始化一个值
                        }
                        tempType = pro.PropertyType;//将属性的类型赋值给Temp
                    }
                }

                var fproperty = tempType.GetProperty(level.Last());//根据属性的名字得到属性的对象
                if (fproperty == null)//空的话返回
                {
                    return;
                }
                if (value == null)//给Tmep对象设置值
                {
                    fproperty.SetValue(temp, value, null);
                }

                bool isArray = false; //判断Value是不是数组
                if (value != null && value.GetType().IsArray == true)
                {
                    isArray = true;
                }

                if (stringBasedValue == true)//是否为数组
                {
                    Type propertyType = fproperty.PropertyType;
                    if (propertyType.IsGenericType && propertyType.GetGenericTypeDefinition() == typeof(List<>))
                    {
                        var list = propertyType.GetConstructor(Type.EmptyTypes).Invoke(null) as IList;

                        var gs = propertyType.GenericTypeArguments;
                        try
                        {
                            if (isArray)
                            {
                                var a = (value as object[]);
                                for (int i = 0; i < a.Length; i++)
                                {
                                    list.Add(ConvertValue(a[i], gs[0]));
                                }
                            }
                        }
                        catch { }
                        fproperty.SetValue(temp, list, null);
                    }
                    else
                    {
                        if (isArray)
                        {
                            var a = (value as object[]);
                            if (a.Length == 1)
                            {
                                value = a[0];
                            }
                        }

                        object val = ConvertValue(value, fproperty.PropertyType);
                        fproperty.SetValue(temp, val, null);
                    }
                }
                else
                {
                    fproperty.SetValue(temp, value, null);
                }
            }
            catch { }
        }

        private static object ConvertValue(object value, Type propertyType)
        {
            object val = null;
            if (propertyType.IsGenericType && propertyType.GetGenericTypeDefinition() == typeof(Nullable<>))
            {
                var gs = propertyType.GenericTypeArguments;
                try
                {
                    val = ConvertValue(value, gs[0]);
                }
                catch { }
            }
            else if (propertyType.IsEnum)
            {
                val = Enum.Parse(propertyType, value.ToString());
            }
            else if (propertyType == typeof(string))
            {
                val = value == null ? null : value.ToString().Trim();
            }
            else if (propertyType == typeof(Guid))
            {
                Guid g = Guid.Empty;
                Guid.TryParse(value.ToString(), out g);
                val = g;
            }
            else
            {
                try
                {
                    if (value.ToString().StartsWith("`") && value.ToString().EndsWith("`"))
                    {
                        string inner = value.ToString().Trim('`').TrimEnd(',');
                        if (!string.IsNullOrWhiteSpace(inner))
                        {
                            val = propertyType.GetConstructor(Type.EmptyTypes).Invoke(null);
                            string[] pair = inner.Split(',');
                            var gs = propertyType.GetGenericArguments();
                            foreach (var p in pair)
                            {
                                (val as IList).Add(Convert.ChangeType(p, gs[0]));
                            }
                        }
                    }
                    else
                    {
                        val = Convert.ChangeType(value.ToString(), propertyType);
                    }
                }
                catch
                {
                }
            }
            return val;
        }
            
    }
}
